package com.boss.salary.service.impl;

import com.boss.common.service.ICommonService;
import com.boss.common.util.DateUtils;
import com.boss.salary.constant.SystemDictConstant;
import com.boss.salary.dao.*;
import com.boss.salary.entity.*;
import com.boss.salary.service.IFormulaManageService;
import com.boss.salary.service.IRedisService;
import com.boss.salary.service.ISalaryHistoryAsyncService;
import com.boss.salary.vo.SalaryMonthEndVO;
import com.boss.sys.ca.user.dto.UserDTO;
import com.boss.sys.utils.SysUtils;
import com.singularsys.jep.JepException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@EnableAsync
public class SalaryHistoryAsyncServiceImpl implements ISalaryHistoryAsyncService {
    /**
     * 引入日志框架常量
     */
    private static final Logger logger = LoggerFactory.getLogger(SalaryHistoryAsyncServiceImpl.class);
    private static DateFormat df = new SimpleDateFormat("yyyy-MM");
    @Autowired
    private IRedisService redisService;
    @Autowired
    private IPersonOperateDao personOperateDao;
    @Autowired
    private IAgencyInfoDao agencyInfoDao;
    @Autowired
    private IPayMentLockDao iPayMentLockDao;
    @Autowired
    private ICommonService commonService;
    @Autowired
    private ISalaryBasedataDao salaryBasedataDao;
    @Autowired
    private ISalaryMonthBeginDao salaryMonthBeginDao;
    @Autowired
    private IPersonExtBeginDao personExtBeginDao;
    @Autowired
    private IPersonExtDao personExtDao;
    @Autowired
    private ISalaryHistoryDao iSalaryHistoryDao;
    @Autowired
    private ISalaryMonthEndDao iSalaryMonthEndDao;
    @Autowired
    private IAgencyVerifyDao iAgencyVerifyDao;
    @Autowired
    private IAgencyInfoDao iAgencyInfoDao;
    @Autowired
    private IPersonInfoDao iPersonInfoDao;
    @Autowired
    private IFormulaManageService formulaManageService;
    @Autowired
    private ISalaryMonthEndSubmitDao salaryMonthEndSubmitDao;
    @Autowired
    private IPersonExtSubmitDao personExtSubmitDao;


    @Autowired
    private IPaymentBackHistoryDao paymentBackHistoryDao;


    private Class<? extends Object> clazz = null;
    private Method[] methods = null;
    private static final String COLUMN_PREFIX = "getS";
    /**
     * 缓解月结数据库超时问题通过循环分成小的事务
     * @param year
     * @param province
     * @param agencyIds
     * @param monthMap
     * @param agencyNameMap
     * @param agencyCodeMap
     * @param personOperateUpdateList
     * @throws ParseException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws JepException
     */
    @Async
    @Override
    public  void saveMonthEndAsynchronous(Integer year, String province, List<String> agencyIds, Map<String, String> monthMap, Map<String, String> agencyNameMap, Map<String, String> agencyCodeMap, List<Object[]> personOperateUpdateList, String uuid,String tokenid, UserDTO userDTO) throws ParseException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, JepException {
        StringBuffer requestMessage=new StringBuffer();
        DecimalFormat df=new DecimalFormat("0.00");
        logger.info("=======单位月结异步方法开始==============");
        for(int i=0;i<agencyIds.size();i++){
            saveMonthEnds(year,province,agencyIds.get(i),monthMap,agencyNameMap,agencyCodeMap,personOperateUpdateList,requestMessage,tokenid,userDTO);
            redisService.put(uuid,df.format((float)(i+1)/agencyIds.size()));
            System.out.println(df.format((float)(i+1)/agencyIds.size()));
            if(i+1==agencyIds.size()){
                redisService.del(province+"lunarKnot");
            }
        }
        if(StringUtils.isEmpty(requestMessage.toString())) {
            redisService.put(uuid, "S");
//            redisService.del(uuid);
        }else{
           // requestMessage.append("F");
            redisService.put(uuid,"F-"+requestMessage.toString());
//            redisService.del(uuid);
        }
        logger.info("=======单位月结异步方法结束==============");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public  void saveMonthEnds(Integer year, String province, String agencyId, Map<String, String> monthMap, Map<String, String> agencyNameMap, Map<String, String> agencyCodeMap, List<Object[]> personOperateUpdateList, StringBuffer requestMessage, String tokenid, UserDTO userDTO) throws ParseException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, JepException {
        AgencyInfo agencyName=agencyInfoDao.selectFirstAuthAgencyData(agencyId);
        try{
            //Thread.currentThread().sleep(300);
            // 批量修改单位审核表的上报状态后，增加下个月的初始数据
            logger.info("==================批量修改审核表数据 Begin ================");
            batchAgencyVerify(year, province,agencyId, monthMap,agencyNameMap,agencyCodeMap);
            logger.info("==================批量修改审核表数据 End ================");

            logger.info("==================批量存储单位历史表数据 Begin ================");
            // 将单位信息存储到历史表
            batchSaveAgencyHistory(province,agencyId, monthMap);
            logger.info("==================批量存储单位历史表数据 End ================");
            logger.info("==================批量存储人员历史表数据 Begin ================");
            // 将人员信息存储到历史表
            batchSavePersonHistory(province,agencyId, monthMap);
            logger.info("==================批量存储人员历史表数据 End ================");
            logger.info("==================批量存储工资表历史表数据 Begin ================");
            // 转换工资表数据并添加到历史表
            batchSaveSalaryHistory(province,agencyId, monthMap);
            logger.info("==================批量存储工资表历史表数据 End ================");
            logger.info("==================批量存储工资表月初表数据 Begin ================");
            // 转换工资表数据并添加到历史表
            batchSaveSalaryMonthBegin(province, agencyId);
            logger.info("==================批量存储工资表月初表数据 End ================");
            logger.info("==================批量存储支付回盘数据 Begin ================");
            //支付回盘信息保存到历史表中，同时清空回盘信息
            batchPaymentBack(agencyId,monthMap);
            logger.info("==================批量存储支付回盘数据 End ================");
            logger.info("==================批量存储银行回盘数据 Begin ================");
            //银行回盘信息保存到历史表中，同时清空回盘信息
            batchBankBack(agencyId,monthMap);
            logger.info("==================批量存储银行回盘数据 End ================");
            //若自动上报单位不为空则修改上月编报的数据为本月
            if(!CollectionUtils.isEmpty(personOperateUpdateList)){
                //将personOperateUpdateList才分 如果id相等走方法
                for(Object[] personOperate:personOperateUpdateList){
                    for(int i=0;i<personOperate.length;i++ ){
                        if(personOperate[i].equals(agencyId)){
                            // 批量修改自动上报单位上月修改数据状态改为下个月
                            logger.info("==================批量修改自动上报单位上月修改数据状态改为下个月 Begin ================");
                            personOperateDao.batchUpdateAutoMonthEnd(personOperateUpdateList);
                            logger.info("==================批量修改自动上报单位上月修改数据状态改为下个月 End ================");
                            logger.info("==================批量修改自动上报单位上月附件数据状态改为下个月 Begin ================");
                            personOperateDao.batchUpdateAutoFile(personOperateUpdateList);
                            logger.info("==================批量修改自动上报单位上月附件数据状态改为下个月 End ================");
                        }
                    }
                }
            }
            //获取已锁定指标
            List<String> agencyIds=new ArrayList<>();
            agencyIds.add(agencyId);
            List<Map<String,Object>> payLockMap=iPayMentLockDao.selectPayMentLock(agencyIds);
            //解冻指标
            if(!CollectionUtils.isEmpty(payLockMap)) {
                commonService.batchGocpurbudgetThaw(payLockMap, province, year+"", tokenid,userDTO);
            }
        }catch (Exception e){
            logger.info("月结后续方法错误：",e);
            requestMessage.append(agencyName.getAgencyName());
        }

    }

    void batchAgencyVerify(Integer year, String province, String agencyId, Map<String, String> monthMap, Map<String, String> nameMap, Map<String, String> codeMap) throws ParseException {

        String currentTime = String.valueOf(DateUtils.getCurrentTimeStamp());
        //    批量更新单位审核表上报状态集合
        List<Object[]> agencyVerifyUpdatelist = new ArrayList<>();
        //    批量插入单位审核表参数集合
        List<Object[]> agencyVerifyInsertlist = new ArrayList<>();

        // 获取批量更新和批量插入的参数
//        for (String agencyId : agencyIds) {
        // 当前月
        String currentMonth = monthMap.get(agencyId);
        String agencyName = nameMap.get(agencyId);
        String agencyCode = codeMap.get(agencyId);
        // 获取下个月
        Date date = df.parse(currentMonth);
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), zoneId);
        String nextMonth = localDateTime.plusMonths(1).format(DateTimeFormatter.ofPattern("yyyy-MM"));
        String nextYear = localDateTime.plusMonths(1).format(DateTimeFormatter.ofPattern("yyyy"));

        // 批量更新参数集合
        Object[] updateObjects = new Object[]{
                SystemDictConstant.IS_TRUE, currentTime, agencyId, currentMonth
        };
        agencyVerifyUpdatelist.add(updateObjects);
        // 批量插入参数集合
        Object[] insertObjects = new Object[]{
                SysUtils.generateGuid(), SysUtils.generateGuid(), currentTime, currentTime, agencyId, nextMonth,
                SystemDictConstant.NO_SUBMIT,
                SystemDictConstant.NO_SUBMIT, SystemDictConstant.NO_SUBMIT, SystemDictConstant.NO_SUBMIT,
                SystemDictConstant.IS_FALSE, SystemDictConstant.IS_FALSE, SystemDictConstant.IS_FALSE,
                SystemDictConstant.IS_FALSE, SystemDictConstant.IS_FALSE, SystemDictConstant.IS_FALSE,
                SystemDictConstant.IS_FALSE, "", "", SystemDictConstant.IS_FALSE, 0, 0, 0, 0, 0, SystemDictConstant.IS_FALSE,
                province, nextYear,0,agencyName,agencyCode
        };
        agencyVerifyInsertlist.add(insertObjects);
//        }


        // 批量更新单位审核表月结状态
        iAgencyVerifyDao.batchUpdateMonthEnd(agencyVerifyUpdatelist);
        // 批量增加单位审核表下个月的初始数据
        iAgencyVerifyDao.batchInsertInitDate(agencyVerifyInsertlist);
    }
    /**
     * 批量插入单位信息到历史表
     *
     * @param agencyId
     * @param monthMap
     */
    void batchSaveAgencyHistory(String province, String agencyId, Map<String, String> monthMap) {
        // 根据id获取单位信息
        AgencyInfo agencyInfo = iAgencyInfoDao.selectFirstAuthAgencyData(agencyId);
//        if (agencyInfoList.size() > 0) {
        String currentTime = String.valueOf(DateUtils.getCurrentTimeStamp());
        List<Object[]> saveList = new ArrayList<>();
//            for (AgencyInfo agencyInfo : agencyInfoList) {
        Object[] objects = new Object[]{
                SysUtils.generateGuid(), agencyInfo.getId(), agencyInfo.getBizKey(), currentTime, currentTime,
                monthMap.get(agencyInfo.getId()), agencyInfo.getId(), agencyInfo.getAgencyAddress(), agencyInfo.getZip(),
                agencyInfo.getAgencyAdmLevelCode(), agencyInfo.getAdmDepTypeCode(), agencyInfo.getAgencyBankName(),
                agencyInfo.getAgencyBankCardno(), agencyInfo.getCentralAgencyCode(), agencyInfo.getAgencyLeader(),
                agencyInfo.getIsUniSala(), agencyInfo.getRemarks(), agencyInfo.getHasFile(), agencyInfo.getFundSupCode(),
                agencyInfo.getCapitalType(), agencyInfo.getVerifyState(), agencyInfo.getEffectiveYear(),
                agencyInfo.getIsDeleted(),province,agencyInfo.getAgencyName(),agencyInfo.getAgencyCode(),agencyInfo.getParentId()
        };
        saveList.add(objects);
//            }
        // 批量插入到历史表
        iAgencyInfoDao.batchSaveAgencyHistory(saveList);
//        }
    }

    /**
     * 批量插入人员信息到历史表
     *
     * @param agencyId
     * @param monthMap
     */
    void batchSavePersonHistory(String province, String agencyId, Map<String, String> monthMap) {
        // 根据单位id获取用户信息
        List<PersonInfo> personInfoList = iPersonInfoDao.getPersonInfoByAgencyIds(agencyId);
//        if (personInfoList.size() > 0) {
        String currentTime = String.valueOf(DateUtils.getCurrentTimeStamp());
        List<Object[]> saveList = new ArrayList<>();
        for (PersonInfo personInfo : personInfoList) {
            Object[] objects = new Object[]{
                    SysUtils.generateGuid(), personInfo.getId(), monthMap.get(personInfo.getAgencyId()), currentTime, currentTime,
                    personInfo.getId(), personInfo.getPersonAddress(), personInfo.getAgencyId(), personInfo.getDeptId(),
                    personInfo.getAgencyCode(), personInfo.getEnterAgencyDate(), personInfo.getRetireDate(),
                    personInfo.getPersonTypeCode(), personInfo.getPersonIdeCode(), personInfo.getEndDate(),
                    personInfo.getDeadDate(), personInfo.getRemarks(), personInfo.getSalaCardNo(), personInfo.getSalaCardBank(),
                    personInfo.getGovCredCardNo(), personInfo.getGovCredCardBank(), personInfo.getStartDate(),
                    personInfo.getMeritPayCode(), personInfo.getSchRecCode(), personInfo.getPosCode(), personInfo.getGrCode(),
                    personInfo.getTecGrCode(), personInfo.getIsAuth(), personInfo.getSalaGrCode(), personInfo.getPersonState(),
                    personInfo.getChangeState(), personInfo.getPerSourceCode(), personInfo.getIsSpecialPost(),
                    personInfo.getIsInsurance(), personInfo.getIsUniSala(), personInfo.getIsStopSalary(), personInfo.getIsDeleted(),province,
                    personInfo.getPersonTypeId(), personInfo.getPostId(), personInfo.getGradeId(), personInfo.getLevelId(),personInfo.getPersonName(),
                    personInfo.getIdenNo(),personInfo.getState(),personInfo.getShowOrder(),personInfo.getPhone(),personInfo.getPersonnelCode(),
                    personInfo.getFuncCode(),personInfo.getFuncName(),personInfo.getFuncCode()
            };
            saveList.add(objects);
        }
        // 批量插入到历史表
        iPersonInfoDao.batchSavePersonHistory(saveList);
//       }
    }

    /**
     * 转换工资表的数据，并批量存储到数据库历史表
     *
     * @param agencyIds
     * @param monthMap
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    void batchSaveSalaryHistory(String province, String agencyIds, Map<String, String> monthMap) throws InvocationTargetException, IllegalAccessException {
        // 获取当月表中对应单位的数据
        List<SalaryMonthEnd> salaryMonthEndList = iSalaryMonthEndDao.getSalaryMonthEndByAgencyIds(agencyIds);
        // 最终参数集合
        List<Object[]> lists = new ArrayList<>();
        // 将当月表的数据复制到历史表中
        for (SalaryMonthEnd salaryMonthEnd : salaryMonthEndList) {
            clazz = null;
            methods = null;
            // 转换工资表数据并添加到历史表
            List<Object> list = new ArrayList<>();
            // 历史表id
            list.add(SysUtils.generateGuid());
            // 历史表对应的工资表id
            list.add(salaryMonthEnd.getId());
            // 历史表创建时间
            list.add(String.valueOf(DateUtils.getCurrentTimeStamp()));
            // 历史表更新时间
            list.add(String.valueOf(DateUtils.getCurrentTimeStamp()));
            // 历史表月结时间
            list.add(monthMap.get(salaryMonthEnd.getAgencyId()));
            // 历史表单位id
            list.add(salaryMonthEnd.getAgencyId());
            // 历史表人员id
            list.add(salaryMonthEnd.getPersonId());
            // 是否十三月工资
            list.add(salaryMonthEnd.getIsThirteen());
            //区划
            list.add(province);
            // 历史表 s1~s100
            for (int i = 1; i < 101; i++) {
                list.add(converBeanFiledForObject(salaryMonthEnd, COLUMN_PREFIX + i));
            }
            // 将数据存储到最终要保存的数组中
            lists.add(list.toArray());
        }

        // 将数据批量插入到历史表
        iSalaryHistoryDao.batchSaveSalaryHistory(lists);
    }

    /**
     * 通过反射类，获取字段值
     *
     * @param bean
     * @param column
     * @param <T>
     * @return
     */
    private <T> Object converBeanFiledForObject(T bean, String column) throws InvocationTargetException, IllegalAccessException {
        Object object = null;
        if (clazz != null && methods != null) {
            for (Method method : methods) {
                if (column.equals(method.getName())) {
                    object = method.invoke(bean);
                    break;
                }
            }
        } else {
            clazz = bean.getClass();
            methods = clazz.getDeclaredMethods();
            if (methods.length > 0) {
                for (Method method : methods) {
                    if (column.equals(method.getName())) {
                        object = method.invoke(bean);
                        break;
                    }
                }
            }
        }
        return object;
    }

    /**
     * 月结清零并计算，批量保存到月初表中
     * @param province
     * @param agencyId
     */
    void batchSaveSalaryMonthBegin(String province, String agencyId) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, JepException {
//        查询需要清零的工资项
        List<String> clearSalaryLIst = salaryBasedataDao.selectClearColumn(province);
//      查询需要操作的人员工资
//        List<SalaryMonthEndVO> salaryMonthEndSubmitVOList= new ArrayList<>();
//        List<SalaryMonthEndVO>  salaryMonthEndVOList=new ArrayList<>();
        List<String> agencyIds= new ArrayList<>();
        agencyIds.add(agencyId);
        //       / List<SalaryMonthEndVO salaryMonthEndSubmitVOList = iSalaryMonthEndDao.selectSalaryMonthEndSubmitWithSalaryType(province, agencyIds);
        List<SalaryMonthEndVO> salaryMonthEndSubmitVOList = iSalaryMonthEndDao.selectSalaryMonthEndSubmitWithSalaryTypes(province, agencyId);
//        List<SalaryMonthEndVO> salaryMonthEndVOList = iSalaryMonthEndDao.selectSalaryMonthEndWithSalaryType(province, agencyIds);
        List<SalaryMonthEndVO> salaryMonthEndVOList = iSalaryMonthEndDao.selectSalaryMonthEndWithSalaryTypes(province, agencyId);
//        如果没有需要清零的工资项，则直接保存到月初表中
        if(!CollectionUtils.isEmpty(clearSalaryLIst)){
            Class<?> salaryMonthEndVOClass = SalaryMonthEndVO.class;
//            将清零项都设置为0
            for(SalaryMonthEndVO salaryMonthEndSubmitVO : salaryMonthEndSubmitVOList){
                for(String column : clearSalaryLIst){
                    Method setMethod = salaryMonthEndVOClass.getDeclaredMethod("set" + column.substring(0,1).toUpperCase() + column.substring(1), Double.class);
                    setMethod.invoke(salaryMonthEndSubmitVO, Double.parseDouble("0"));
                }
            }

            salaryMonthEndSubmitVOList = formulaManageService.calculateByFormula(province, agencyIds, salaryMonthEndSubmitVOList);
            //        单位端数据如果没有需要清零的工资项，则直接保存到月初表中 将清零项都设置为0
            for(SalaryMonthEndVO salaryMonthEndVO : salaryMonthEndVOList){
                for(String column : clearSalaryLIst){
                    Method setMethod = salaryMonthEndVOClass.getDeclaredMethod("set" + column.substring(0,1).toUpperCase() + column.substring(1), Double.class);
                    setMethod.invoke(salaryMonthEndVO, Double.parseDouble("0"));
                }
            }

            salaryMonthEndVOList = formulaManageService.calculateByFormula(province, agencyIds, salaryMonthEndVOList);
        }



        // 保存修改后工资
        iSalaryMonthEndDao.batchUpdateSalaryMonthEnd(salaryMonthEndVOList);
//        将之前这些机构的月初工资数据清除
        salaryMonthBeginDao.batchPhysicalDeleteSalaryMonthBegin(province, agencyIds);
        salaryMonthBeginDao.batchSaveSalaryMonthBegin(salaryMonthEndSubmitVOList);
        personExtBeginDao.batchPhysicalDeletePersonExtBegin(province, agencyIds);
        List<PersonExt> personExts=personExtDao.queryPersonExtSubmit(agencyIds);
        personExtBeginDao.batchSavePersonExtBegin(personExts);
        //月结时清空该单位上报数据
        salaryMonthEndSubmitDao.batchPhysicalDeleteSalaryMonthSubmit(province, agencyIds);
        personExtSubmitDao.batchPhysicalDeletePersonExtSubmit(province, agencyIds);
    }

    /**
     * 月结批量处理支付回盘数据
     * @param agencyIds
     * @param monthMap
     */
    void batchPaymentBack(String agencyIds, Map<String, String> monthMap) {
        List<SalaryPaymentRequisitionBack> spList=paymentBackHistoryDao.getPayBackData(agencyIds);
        paymentBackHistoryDao.deletePayBackData(agencyIds);
        paymentBackHistoryDao.batchInsertPayBackHistoryData(spList,monthMap);

    }
//    private void batchPaymentBack(String agencyIds,Map<String, String> monthMap) {
//
//    }

    /**
     * 月结批量处理银行回盘数据
     * @param agencyIds
     * @param monthMap
     */
    void batchBankBack(String agencyIds, Map<String, String> monthMap) {

        List<SalaryBankPayBack> spList=paymentBackHistoryDao.getBankBackData(agencyIds);
        paymentBackHistoryDao.deleteBankBackData(agencyIds);
        paymentBackHistoryDao.batchInsertBankBackHistoryData(spList,monthMap);
    }

}
